#include "LecteurPhraseSimple.h"
#include "MotsCles.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseSimple::LecteurPhraseSimple(string nomFich) :
	ls(nomFich) {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::programme() {
// <programme> ::= debut <seqInst> fin FIN_FICHIER
	
	sauterSymCour(DEBUT);
	seqInst();
	sauterSymCour(FIN);
	testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::seqInst() {
// <seqInst> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while  (ls.getSymCour()!=FIN && ls.getSymCour()!=FINTANTQUE &&
	ls.getSymCour()!=JUSQUA && ls.getSymCour()!=FINSI && 
	ls.getSymCour()!=SINON && ls.getSymCour()!=SINONSI && 
	ls.getSymCour()!=FINPOUR);
	// (ls.getSymCour()!="fin" || ls.getSymCour()!="fintantque" || ls.getSymCour()!="finsi" || ls.getSymCour()!="sinon" || ls.getSymCour()!="sinonsi");
	// tant que le symbole courant est un debut possible d'instruction...
	//while (ls.getSymCour()=="<VARIABLE>");
}

////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::inst() {
// <inst> ::= <affectation>

	affectation();
}*/
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::inst()
//    <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instLire> | <instEcrire>
{
	if (ls.getSymCour()=="<VARIABLE>")
		affectation();
	else if (ls.getSymCour()==SI) // on lance la "conditionr qui contiendra elle-meme des instructions. (condition = ExpBool)
		instSi();
	else if (ls.getSymCour()==TANTQUE) // idem que if
		instTq();
	else if (ls.getSymCour()==REPETER) // idem que if
		instRepeter();
	else if (ls.getSymCour()==POUR) // idem que if
		instPour();
	else if (ls.getSymCour()==LIRE) // instruction pour lire une variable au clavier. (accepte que des <VARIABLE>
		instLire();
	else if (ls.getSymCour()==ECRIRE) // instruction pour ecrire a l'ecran des variable, entier, chaine.
		instEcrire();
    else
	erreur("<inst>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::instSi()
//  <instSi> ::= si ( <expBoolOu> ) <seqInst> { sinonsi ( <expBoolOu> ) <seqInst> }
//  [ sinon <seqInst> ] finsi
{
	ls.suivant();
	sauterSymCour("(");
	expBoolOu();
	sauterSymCour(")");
	seqInst();
	while (ls.getSymCour()==SINONSI) {
		ls.suivant();
		sauterSymCour("(");
		expBoolOu();
		sauterSymCour(")");
		seqInst();
	}
	if (ls.getSymCour()==SINON) {
		ls.suivant();
		seqInst();
	}
	sauterSymCour(FINSI);
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::instTq()
// <instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
{
	ls.suivant();
	sauterSymCour("(");
	expBoolOu();
	sauterSymCour(")");
	seqInst();
	sauterSymCour(FINTANTQUE);
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::instPour()
// <instPour> ::= pour ( affectation ; <expBool>; affectation ) <seqInst> finpour
{
  	ls.suivant();
	sauterSymCour("(");
	affectation();
	sauterSymCour(";");
	expBoolOu();
	sauterSymCour(";");
	affectation();
	sauterSymCour(")");
	seqInst();
	sauterSymCour(FINPOUR);
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::instRepeter()
// <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
{
	ls.suivant();
	seqInst();
	sauterSymCour(JUSQUA);
	sauterSymCour("(");
	expBoolOu();
	sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::instLire() //<instLire> ::= lire ( <variable> )
{
	sauterSymCour(LIRE);
	sauterSymCour("(");
	if (ls.getSymCour()=="<VARIABLE>") {
		facteur();
		sauterSymCour(")");
	}
	else
		erreur("<variable>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::instEcrire() //   <instEcrire> ::= ecrire ( <expression> | <chaine> )
{
	sauterSymCour(ECRIRE);
	sauterSymCour("(");
	if (ls.getSymCour()=="<STRING>") {
		ls.suivant();
	}
	else
		expression();
	sauterSymCour(")");
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::affectation() {
// <affectation> ::= <variable> = <expression>

	sauterSymCour("<VARIABLE>");
	sauterSymCour("=");
	expression();
}


////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::expBool()
// <expBool> ::= <relation> { <opBool> <relation> }
{
	if (ls.getSymCour()==NON) {
			sauterSymCour(NON);
	}
	relation();
	while (ls.getSymCour()==ET || ls.getSymCour()==OU) {
		opBool();
		ls.suivant();
		relation();
	}
}*/

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::expBoolOu()
// <expBool> ::= <expBoolEt> { <opOu> <expBoolOu> }
{
	expBoolEt();
	while (ls.getSymCour()==OU) {
		opOu();
		expBoolEt();
	}

}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::expBoolEt()
// <expBoolEt> ::= <relation> { <opEt> <expBoolOu> }
{
	relation();
	while (ls.getSymCour()==ET) {
		opEt();
		relation();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::relation()
// <relation> ::= <expBool> { <opRel> <expBool> }
// <expression> { <opRel> <expression> }
{
	expression();
	while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" ||
			ls.getSymCour()=="<" || ls.getSymCour()=="<=" ||
			ls.getSymCour()==">" || ls.getSymCour()==">=") {
		opRel();
		expression();
	}

}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::expression() {
// <expression> ::= <terme> { <opAdd> <terme> }
	terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		opAdd();
		terme();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::terme() {
// <terme> ::= <facteur> { <opBinaire> <facteur> }
	//cout << "trace 2" << endl;
	facteur();

	while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		opMult();
		facteur();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
// <facteur> ::= <entier> | <variable> | <opUnaire> <expBool> | ( <expBool> )
	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
		ls.suivant();
	}
	else if ((ls.getSymCour()=="-") || (ls.getSymCour()==NON))  {
		opUnaire();
		facteur();
	}
	else if (ls.getSymCour()=="(") {
	  	sauterSymCour("(");
		expBoolOu();
		sauterSymCour(")");
	}
	else
	erreur("<facteur>");
}



////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::opBinaire()
// <opBinaire> ::= + | - | *  | /
{
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" || 
		ls.getSymCour()=="*" || ls.getSymCour()=="/")
		ls.suivant();
	else
		erreur("<opBinaire>");
}*/

/*////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opBool()
// <opBool> ::= et | ou
{
	if (ls.getSymCour()==ET || ls.getSymCour()==OU)
		ls.suivant();
	else
		erreur("<opBool>");

}*/

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opEt()
// <opBool> ::= et
{
	if (ls.getSymCour()==ET)
		ls.suivant();
	else
		erreur("<opBoolEt");

}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opOu()
// <opBool> ::= ou
{
	if (ls.getSymCour()==OU)
		ls.suivant();
	else
		erreur("<opBoolOu>");

}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opRel()
// <opRel> ::= == | != | < | <= | > | >=
{

	if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" ||
		ls.getSymCour()=="<" || ls.getSymCour()=="<=" ||
		ls.getSymCour()==">" || ls.getSymCour()==">=")
		ls.suivant();
	else
		erreur("<opRel>");

}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opUnaire()
// <opUnaire> ::= - | non
{

	if (ls.getSymCour()=="-" || ls.getSymCour()==NON)
		ls.suivant();
	else
		erreur("<opUnaire>");

}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opAdd()
// <opAdd> ::= + | -
{
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
		ls.suivant();
	else
		erreur("<opAdd>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opMult()
// <opMult> ::= *  | /
{
	if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
		ls.suivant();
	else
		erreur("<opMult>");
}




////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}



